package com.iwhalecloud.citybrain.flow.platform.manager.application.service.impl.task;

import com.alibaba.cola.dto.Response;
import com.alibaba.fastjson.JSONObject;
import com.iwhalecloud.citybrain.flow.platform.manager.application.service.TaskCreatedPostProcessor;
import com.iwhalecloud.citybrain.flow.platform.manager.application.service.UserService;
import com.iwhalecloud.citybrain.flow.platform.manager.application.service.UserTaskManageService;
import com.iwhalecloud.citybrain.flow.platform.manager.application.utils.DateUtils;
import com.iwhalecloud.citybrain.flow.platform.manager.application.utils.FlowUtils;
import com.iwhalecloud.citybrain.flow.platform.manager.application.utils.ParseRenderedVariable;
import com.iwhalecloud.citybrain.flow.platform.manager.application.utils.StringUtils;
import com.iwhalecloud.citybrain.flow.platform.manager.common.ConstanceVariable;
import com.iwhalecloud.citybrain.flow.platform.manager.common.ErrorCode;
import com.iwhalecloud.citybrain.flow.platform.manager.common.ResponseResult;
import com.iwhalecloud.citybrain.flow.platform.manager.common.client.HttpTaskTraceDto;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.enums.MsgTypeEnum;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.exception.EventCallSuspendException;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.FlowFormExternalInfoDomain;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.FlowProcessInstanceTraceVo;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.ModelCustomConfigDomain;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.app.FlowApp;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.eventconfig.EventExceptionDomain;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.monitor.FlowTaskTraceVo;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.notice.FlowReTimeoutSettingVo;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.userentity.CandidateEntity;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.userentity.UserInfo;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.repository.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.identitylink.service.impl.persistence.entity.IdentityLinkEntity;
import org.flowable.task.service.impl.persistence.entity.TaskEntity;
import org.flowable.task.service.impl.persistence.entity.TaskEntityImpl;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 　　* @description: 同步待办任务信息给第三方
 * 　　* @author shenrm
 * 　　* @date 2021/12/22 16:51
 */
@Slf4j
@Service
@Order(99)
public class SyncTaskTracePostProcessor implements TaskCreatedPostProcessor {

    @Autowired
    private FlowTaskTraceRepository flowTaskTraceRepository;

    @Autowired
    private UserService userService;

    @Autowired
    private FlowProcessInstanceTraceRepository flowProcessInstanceTraceRepository;

    @Autowired
    private FlowTitleExpressionResultRepository flowTitleExpressionResultRepository;

    @Autowired
    private TaskService taskService;

    @Autowired
    private UserTaskManageService userTaskManageService;

    @Autowired
    private UserInfoHandleProcessor userInfoHandleProcessor;

    @Autowired
    private FlowTaskService flowTaskService;

    @Autowired
    private RepositoryService repositoryService;

    @Autowired
    private FlowReTimeoutSettingRepository flowReTimeoutSettingRepository;

    @Autowired
    private RuntimeService runtimeService;

    @Autowired
    private FlowReModelCustomConfigRepository flowReModelCustomConfigRepository;

    @Autowired
    private FlowFormRepository flowFormRepository;

    @Autowired
    private FlowAppRepository flowAppRepository;

    @Autowired
    private FlowEventExceptionRepository flowEventExceptionRepository;

    @Autowired
    private EventExceptionHandler eventExceptionHandler;

    /**
     * 时间格式化默认格式
     */
    private final static String DEDALUT_PATTERN = "yyyy-MM-dd HH:mm:ss";

    /**
     * 世界时间格式
     */
    private final static String UTC_WITH_ZONE_OFFSET_PATTERN = "yyyy-MM-dd'T'HH:mm:ssZ";

    /**
     * 任务跳转地址
     */
    @Value("${task.jumpUrl:http://flow-platform-web-daily.ingress.dayu.work/todo/templatepage?actype=todo&processInstanceId=:processInstanceId&taskId=:taskId}")
    private String jumpUrl;

    /**
     * 任务来源应用编码
     */
    @Value("${task.sourceAppCode:mes2}")
    private String sourceAppCode;

    @Override
    public void process(TaskEntity taskEntity) throws EventCallSuspendException {
        log.info("SyncTaskTracePostProcessor流程组件批量新增待办同步待办组件入参：{}", taskEntity);
        if (Objects.isNull(taskEntity)) {
            return;
        }
    }


    private List<UserInfo> resolveUserIdsByDataType(TaskEntity taskEntity) {
        // 按类型封装
        Set<CandidateEntity> candidateEntitySet = new HashSet<>();

        // 校验是否是会签节点,如果是会签节点,则查询identityLink
        List<IdentityLinkEntity> identityLinkList = ((TaskEntityImpl) taskEntity).getIdentityLinks();
        if (CollectionUtils.isNotEmpty(identityLinkList)) {
            for (IdentityLinkEntity identityLink : identityLinkList) {
                //删除的不参与计算
                if (identityLink.isDeleted()) {
                    continue;
                }
                String candidateType = identityLink.getType();
                String userId = identityLink.getUserId();
                String groupId = identityLink.getGroupId();
                if (Objects.equals("candidate", candidateType)) {
                    if (StringUtils.isNotBlank(userId)) {
                        CandidateEntity candidateEntity = userInfoHandleProcessor.convertObjectToCandidate("STA", userId);
                        candidateEntitySet.add(candidateEntity);
                    } else if (StringUtils.isNotBlank(groupId)) {
                        CandidateEntity candidateEntity = userInfoHandleProcessor.convertObjectToCandidate("ORG", groupId);
                        candidateEntitySet.add(candidateEntity);
                    }
                } else {
                    if (Objects.equals("STA", candidateType) || Objects.equals("assignee", candidateType)) {
                        CandidateEntity candidateEntity = userInfoHandleProcessor.convertObjectToCandidate(candidateType, userId);
                        candidateEntitySet.add(candidateEntity);
                    } else {
                        CandidateEntity candidateEntity = userInfoHandleProcessor.convertObjectToCandidate(candidateType, groupId);
                        candidateEntitySet.add(candidateEntity);
                    }
                }
            }
        } else {
            if (StringUtils.isNotBlank(taskEntity.getAssignee())) {
                CandidateEntity candidateEntity = new CandidateEntity();
                candidateEntity.setCode(taskEntity.getAssignee());
                candidateEntity.setType("STA");
                candidateEntitySet.add(candidateEntity);
            }
        }

        // 按照类型解析成具体的人员,批量查询
        Map<String, List<String>> dataMap = userInfoHandleProcessor.convertObjectToDataMap(candidateEntitySet);

        // 分类解析人员信息并过滤userId
        Set<String> filterUserIdSet = userInfoHandleProcessor.resolveUserIds(dataMap);

        // 根据userId批量查询用户信息
        return this.batchGetUserInfos(filterUserIdSet);
    }

    /**
     * 批量获取用户信息
     *
     * @param userIdSet
     * @return
     */
    private List<UserInfo> batchGetUserInfos(Set<String> userIdSet) {
        // 用户信息不为空
        if (CollectionUtils.isNotEmpty(userIdSet)) {
            // 类型转换
            List<String> userIdList = userIdSet.stream().map(userId -> {
                return userId;
            }).collect(Collectors.toList());


            List<UserInfo> userInfoList = userService.getUserListByUserIdList(userIdList);
            return userInfoList;
        }
        return Collections.emptyList();
    }


    /**
     * 根据流程实例轨迹记录组装数据
     *
     * @param processInstanceVo
     * @param flowTaskTraceVo
     * @param httpTaskTraceDto
     */
    private void convertDataByProcessInstanceVo(FlowProcessInstanceTraceVo processInstanceVo, FlowTaskTraceVo flowTaskTraceVo, HttpTaskTraceDto httpTaskTraceDto) {
        if (Objects.nonNull(processInstanceVo)) {
            // 流程发起人员工工号
            httpTaskTraceDto.setCreator(processInstanceVo.getStarterId());
            // 流程发起人员工名称
            httpTaskTraceDto.setCreatorName(processInstanceVo.getStarterName());
            // 紧急程度,0:一般 1:紧急
            httpTaskTraceDto.setIsUrgent(processInstanceVo.getUrgentLevel().intValue() == 1 ? Boolean.TRUE : Boolean.FALSE);
            httpTaskTraceDto.setProcessCreateTime(DateUtils.dateToStr(processInstanceVo.getStartTime(), DEDALUT_PATTERN));
            httpTaskTraceDto.setSourceApplicationNum(sourceAppCode);
            httpTaskTraceDto.setSourceApplicationName(processInstanceVo.getAppName());

            // 需要根据流程实例ID获取对应配置业务appCode传给待办组件查询区分业务使用
            List<FlowApp> flowApps = flowAppRepository.getAppInfoByProcessInstanceId(processInstanceVo.getProcessInstanceId());
            if (CollectionUtils.isNotEmpty(flowApps)) {
                FlowApp flowApp = flowApps.get(0);
                httpTaskTraceDto.setAppCode(flowApp.getAppCode());
            }

            // 查询自定义标题
            httpTaskTraceDto.setTasksContent(this.getCustomTitle(processInstanceVo.getProcessInstanceId(), flowTaskTraceVo.getActivityId()));
        }
    }

    /**
     * 根据任务实例轨迹记录组装数据
     *
     * @param flowTaskTraceVo
     * @param httpTaskTraceDto
     * @param timeoutSettingVo
     * @param warningSettingVo
     */
    private void convertDataByFlowTaskTraceVo(FlowTaskTraceVo flowTaskTraceVo, HttpTaskTraceDto httpTaskTraceDto,
                                              FlowReTimeoutSettingVo timeoutSettingVo, FlowReTimeoutSettingVo warningSettingVo) {
        if (Objects.nonNull(flowTaskTraceVo)) {
            httpTaskTraceDto.setProcessInstanceId(flowTaskTraceVo.getProcessInstanceId());

            httpTaskTraceDto.setTaskInstanceId(flowTaskTraceVo.getTaskId());

            httpTaskTraceDto.setNodeCode(flowTaskTraceVo.getActivityId());

            httpTaskTraceDto.setCreateTime(DateUtils.dateToStr(flowTaskTraceVo.getCreateTime(), DEDALUT_PATTERN));

            httpTaskTraceDto.setProcessCode(flowTaskTraceVo.getModelKey());

            httpTaskTraceDto.setProcessName(flowTaskTraceVo.getModelName());

            httpTaskTraceDto.setProcessNodeStatus(flowTaskTraceVo.getStatus());

            httpTaskTraceDto.setStatus(flowTaskTraceVo.getLinkStatus());

            // 超时时间
            if (Objects.nonNull(timeoutSettingVo)) {
                // 如果任务计划完成时间变量取值不为空,则优先获取变量中的数值
                if (StringUtils.isNotBlank(timeoutSettingVo.getTaskPlanCompTime())) {
                    httpTaskTraceDto.setExpectedCompletionTime(timeoutSettingVo.getTaskPlanCompTime());
                } else {
                    // 获取期望完成时间
                    httpTaskTraceDto.setExpectedCompletionTime(DateUtils.getNewTimeByTimeType(new Date(), Calendar.SECOND
                            , String.valueOf(timeoutSettingVo.getDuration()), DEDALUT_PATTERN));
                }
            }

            // 预警时间
            if (Objects.nonNull(warningSettingVo)) {
                httpTaskTraceDto.setWarningTime(DateUtils.getNewTimeByTimeType(new Date(), Calendar.SECOND
                        , String.valueOf(warningSettingVo.getDuration()), DEDALUT_PATTERN));
            }
        }
    }

    /**
     * 根据公共的参数取组装数据
     *
     * @param taskEntity
     * @param httpTaskTraceDto
     */
    private void convertDataByCommon(TaskEntity taskEntity, FlowTaskTraceVo flowTaskTraceVo, HttpTaskTraceDto httpTaskTraceDto) {
        if (Objects.nonNull(taskEntity)) {
            // 是否转办标识,新增任务,默认是false,在具体触发转办行为成功时,则修改成true
            httpTaskTraceDto.setIsTransfer(Boolean.FALSE);
            // 任务节点名称
            httpTaskTraceDto.setNodeName(taskEntity.getName());

            // 为空时取默认
            String defaultUrl = jumpUrl.replace(":processInstanceId", flowTaskTraceVo.getProcessInstanceId()).replace(":taskId", flowTaskTraceVo.getTaskId());

            // 获取对接门户跳转到待办的链接
            String url = this.getJumpUrl(taskEntity);

            // 外置表单跳转链接是空就取默认配置
            String jumpConnection = url == null ? defaultUrl : url;

            log.info("转换之后外置表单的jumpConnection==>" + jumpConnection);
            // 获取用户任务外置表单跳转url
            httpTaskTraceDto.setJumpConnection(jumpConnection);

            // 该流程实例设置的全局变量
            Map<String, Object> variableMap = runtimeService.getVariables(taskEntity.getProcessInstanceId());
            httpTaskTraceDto.setFieldArea(variableMap);

            // 业务模块编码(业务侧发起传的)
            String businessModuleCodeVar = this.getTaskVariable(ConstanceVariable.BUSINESS_MODULE_CODE, taskEntity);
//            taskEntity.getVariable(ConstanceVariable.BUSINESS_MODULE_CODE, String.class);
            if (StringUtils.isNotBlank(businessModuleCodeVar)) {
                httpTaskTraceDto.setBusinessModuleCode(businessModuleCodeVar);
            }

            // 表单模块编码(业务侧发起传的)
            String formModuleCodeVar = this.getTaskVariable(ConstanceVariable.FORM_MODULE_CODE, taskEntity);
//                    taskEntity.getVariable(ConstanceVariable.FORM_MODULE_CODE, String.class);
            if (StringUtils.isNotBlank(formModuleCodeVar)) {
                httpTaskTraceDto.setFormModuleCode(formModuleCodeVar);
            }
        }
    }

    /**
     * 查询自定义标题
     *
     * @param processInstanceId
     * @param nodeCode
     * @return
     */
    private String getCustomTitle(String processInstanceId, String nodeCode) {
        String customTitle = null;
        try {
            // 流程自定义标题
            customTitle = flowTitleExpressionResultRepository.getTitleExpressionResultByProcessInstanceIdAndActivityId(processInstanceId, nodeCode);
        } catch (Exception ex) {
            log.error("查询自定义标题失败,失败原因:{}", ex.getMessage(), ex);
        }
        return customTitle;
    }

    /**
     * 设置流程发起人
     *
     * @param processInstanceVo
     */
    private void setProcessStartUser(FlowProcessInstanceTraceVo processInstanceVo) {
        if (Objects.nonNull(processInstanceVo) && StringUtils.isNotBlank(processInstanceVo.getStarterId())) {
            // 根据userId获取员工工号
            UserInfo startUserInfo = userService.getUserInfoObj(processInstanceVo.getStarterId());
            processInstanceVo.setStarterId(startUserInfo == null ? null : startUserInfo.getEmployeeCode());
            processInstanceVo.setStarterName(startUserInfo == null ? null : startUserInfo.getUserName());
        }
    }

    private String getJumpUrl(TaskEntity taskEntity) {
        String url = null;
        String deployId = this.getTaskVariable(ConstanceVariable.DEPLOYMENT_ID, taskEntity);
        List<ModelCustomConfigDomain> modelCustomConfigDomainList = flowReModelCustomConfigRepository.listModelConfigByDeployIdAndType(deployId
                , taskEntity.getTaskDefinitionKey(), ConstanceVariable.EXTERNAL_FORM_SHOW_STYLE);
        if (Objects.isNull(modelCustomConfigDomainList) || modelCustomConfigDomainList.isEmpty()) {
            return url;
        }
        String showType = modelCustomConfigDomainList.get(0).getConfig();
        if (Objects.equals(showType, "empty")) {
            String formkey = taskEntity.getFormKey();
            FlowFormExternalInfoDomain flowFormExternalInfoDomain = flowFormRepository.findExternalFormInfo(formkey);
            if (Objects.nonNull(flowFormExternalInfoDomain)) {
                String formUrl = flowFormExternalInfoDomain.getFormUrl();
                url = ParseRenderedVariable.parseRenderedVariable(formUrl, taskEntity);
                log.error("getTaskExternalUrlForTodoComp->url=" + url);
                return url;
            }
        }
        return url;
    }


    public ResponseResult syncUpdateTaskCompTime(String taskId, String newCompTime) {
        ResponseResult responseResult = ResponseResult.success();

            return responseResult;

    }

    public String getModelIdFromProcessDefinition(String processDefinition) {
        if (StringUtils.isBlank(processDefinition)) {
            return processDefinition;
        }
        if (processDefinition.contains(":")) {
            String[] temp = processDefinition.split(":");
            if (temp.length == 3) {
                return temp[2];
            }
        }
        return processDefinition;
    }

    private String getTaskVariable(String variableName, TaskEntity taskEntity) {
        String value = null;
        try {
            value = taskEntity.getVariable(variableName, String.class);
        } catch (Exception ex) {
//            以上方法获取会出现(会出现org.flowable.engine.common.api.FlowableException: lazy loading outside command context、java.lang.NullPointerException: null异常)
            value = taskService.getVariable(taskEntity.getId(), variableName, String.class);
        }
        return value;
    }
}

